1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.google.common.collect;
16
17 import static com.google.common.base.Preconditions.checkNotNull;
18
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.primitives.Booleans;
21
22 import java.io.Serializable;
23 import java.util.NoSuchElementException;
24
25 import javax.annotation.Nullable;
26
27
28
29
30
31
32
33
34
35
36 @GwtCompatible
37 abstract class Cut<C extends Comparable> implements Comparable<Cut<C>>, Serializable {
38 final C endpoint;
39
40 Cut(@Nullable C endpoint) {
41 this.endpoint = endpoint;
42 }
43
44 abstract boolean isLessThan(C value);
45
46 abstract BoundType typeAsLowerBound();
47 abstract BoundType typeAsUpperBound();
48
49 abstract Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain);
50 abstract Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain);
51
52 abstract void describeAsLowerBound(StringBuilder sb);
53 abstract void describeAsUpperBound(StringBuilder sb);
54
55 abstract C leastValueAbove(DiscreteDomain<C> domain);
56 abstract C greatestValueBelow(DiscreteDomain<C> domain);
57
58
59
60
61
62 Cut<C> canonical(DiscreteDomain<C> domain) {
63 return this;
64 }
65
66
67 @Override
68 public int compareTo(Cut<C> that) {
69 if (that == belowAll()) {
70 return 1;
71 }
72 if (that == aboveAll()) {
73 return -1;
74 }
75 int result = Range.compareOrThrow(endpoint, that.endpoint);
76 if (result != 0) {
77 return result;
78 }
79
80 return Booleans.compare(
81 this instanceof AboveValue, that instanceof AboveValue);
82 }
83
84 C endpoint() {
85 return endpoint;
86 }
87
88 @SuppressWarnings("unchecked")
89 @Override public boolean equals(Object obj) {
90 if (obj instanceof Cut) {
91
92 Cut<C> that = (Cut<C>) obj;
93 try {
94 int compareResult = compareTo(that);
95 return compareResult == 0;
96 } catch (ClassCastException ignored) {
97 }
98 }
99 return false;
100 }
101
102
103
104
105
106 @SuppressWarnings("unchecked")
107 static <C extends Comparable> Cut<C> belowAll() {
108 return (Cut<C>) BelowAll.INSTANCE;
109 }
110
111 private static final long serialVersionUID = 0;
112
113 private static final class BelowAll extends Cut<Comparable<?>> {
114 private static final BelowAll INSTANCE = new BelowAll();
115
116 private BelowAll() {
117 super(null);
118 }
119 @Override Comparable<?> endpoint() {
120 throw new IllegalStateException("range unbounded on this side");
121 }
122 @Override boolean isLessThan(Comparable<?> value) {
123 return true;
124 }
125 @Override BoundType typeAsLowerBound() {
126 throw new IllegalStateException();
127 }
128 @Override BoundType typeAsUpperBound() {
129 throw new AssertionError("this statement should be unreachable");
130 }
131 @Override Cut<Comparable<?>> withLowerBoundType(BoundType boundType,
132 DiscreteDomain<Comparable<?>> domain) {
133 throw new IllegalStateException();
134 }
135 @Override Cut<Comparable<?>> withUpperBoundType(BoundType boundType,
136 DiscreteDomain<Comparable<?>> domain) {
137 throw new AssertionError("this statement should be unreachable");
138 }
139 @Override void describeAsLowerBound(StringBuilder sb) {
140 sb.append("(-\u221e");
141 }
142 @Override void describeAsUpperBound(StringBuilder sb) {
143 throw new AssertionError();
144 }
145 @Override Comparable<?> leastValueAbove(
146 DiscreteDomain<Comparable<?>> domain) {
147 return domain.minValue();
148 }
149 @Override Comparable<?> greatestValueBelow(
150 DiscreteDomain<Comparable<?>> domain) {
151 throw new AssertionError();
152 }
153 @Override Cut<Comparable<?>> canonical(
154 DiscreteDomain<Comparable<?>> domain) {
155 try {
156 return Cut.<Comparable<?>>belowValue(domain.minValue());
157 } catch (NoSuchElementException e) {
158 return this;
159 }
160 }
161 @Override public int compareTo(Cut<Comparable<?>> o) {
162 return (o == this) ? 0 : -1;
163 }
164 @Override public String toString() {
165 return "-\u221e";
166 }
167 private Object readResolve() {
168 return INSTANCE;
169 }
170 private static final long serialVersionUID = 0;
171 }
172
173
174
175
176
177 @SuppressWarnings("unchecked")
178 static <C extends Comparable> Cut<C> aboveAll() {
179 return (Cut<C>) AboveAll.INSTANCE;
180 }
181
182 private static final class AboveAll extends Cut<Comparable<?>> {
183 private static final AboveAll INSTANCE = new AboveAll();
184
185 private AboveAll() {
186 super(null);
187 }
188 @Override Comparable<?> endpoint() {
189 throw new IllegalStateException("range unbounded on this side");
190 }
191 @Override boolean isLessThan(Comparable<?> value) {
192 return false;
193 }
194 @Override BoundType typeAsLowerBound() {
195 throw new AssertionError("this statement should be unreachable");
196 }
197 @Override BoundType typeAsUpperBound() {
198 throw new IllegalStateException();
199 }
200 @Override Cut<Comparable<?>> withLowerBoundType(BoundType boundType,
201 DiscreteDomain<Comparable<?>> domain) {
202 throw new AssertionError("this statement should be unreachable");
203 }
204 @Override Cut<Comparable<?>> withUpperBoundType(BoundType boundType,
205 DiscreteDomain<Comparable<?>> domain) {
206 throw new IllegalStateException();
207 }
208 @Override void describeAsLowerBound(StringBuilder sb) {
209 throw new AssertionError();
210 }
211 @Override void describeAsUpperBound(StringBuilder sb) {
212 sb.append("+\u221e)");
213 }
214 @Override Comparable<?> leastValueAbove(
215 DiscreteDomain<Comparable<?>> domain) {
216 throw new AssertionError();
217 }
218 @Override Comparable<?> greatestValueBelow(
219 DiscreteDomain<Comparable<?>> domain) {
220 return domain.maxValue();
221 }
222 @Override public int compareTo(Cut<Comparable<?>> o) {
223 return (o == this) ? 0 : 1;
224 }
225 @Override public String toString() {
226 return "+\u221e";
227 }
228 private Object readResolve() {
229 return INSTANCE;
230 }
231 private static final long serialVersionUID = 0;
232 }
233
234 static <C extends Comparable> Cut<C> belowValue(C endpoint) {
235 return new BelowValue<C>(endpoint);
236 }
237
238 private static final class BelowValue<C extends Comparable> extends Cut<C> {
239 BelowValue(C endpoint) {
240 super(checkNotNull(endpoint));
241 }
242
243 @Override boolean isLessThan(C value) {
244 return Range.compareOrThrow(endpoint, value) <= 0;
245 }
246 @Override BoundType typeAsLowerBound() {
247 return BoundType.CLOSED;
248 }
249 @Override BoundType typeAsUpperBound() {
250 return BoundType.OPEN;
251 }
252 @Override Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) {
253 switch (boundType) {
254 case CLOSED:
255 return this;
256 case OPEN:
257 @Nullable C previous = domain.previous(endpoint);
258 return (previous == null) ? Cut.<C>belowAll() : new AboveValue<C>(previous);
259 default:
260 throw new AssertionError();
261 }
262 }
263 @Override Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) {
264 switch (boundType) {
265 case CLOSED:
266 @Nullable C previous = domain.previous(endpoint);
267 return (previous == null) ? Cut.<C>aboveAll() : new AboveValue<C>(previous);
268 case OPEN:
269 return this;
270 default:
271 throw new AssertionError();
272 }
273 }
274 @Override void describeAsLowerBound(StringBuilder sb) {
275 sb.append('[').append(endpoint);
276 }
277 @Override void describeAsUpperBound(StringBuilder sb) {
278 sb.append(endpoint).append(')');
279 }
280 @Override C leastValueAbove(DiscreteDomain<C> domain) {
281 return endpoint;
282 }
283 @Override C greatestValueBelow(DiscreteDomain<C> domain) {
284 return domain.previous(endpoint);
285 }
286 @Override public int hashCode() {
287 return endpoint.hashCode();
288 }
289 @Override public String toString() {
290 return "\\" + endpoint + "/";
291 }
292 private static final long serialVersionUID = 0;
293 }
294
295 static <C extends Comparable> Cut<C> aboveValue(C endpoint) {
296 return new AboveValue<C>(endpoint);
297 }
298
299 private static final class AboveValue<C extends Comparable> extends Cut<C> {
300 AboveValue(C endpoint) {
301 super(checkNotNull(endpoint));
302 }
303
304 @Override boolean isLessThan(C value) {
305 return Range.compareOrThrow(endpoint, value) < 0;
306 }
307 @Override BoundType typeAsLowerBound() {
308 return BoundType.OPEN;
309 }
310 @Override BoundType typeAsUpperBound() {
311 return BoundType.CLOSED;
312 }
313 @Override Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) {
314 switch (boundType) {
315 case OPEN:
316 return this;
317 case CLOSED:
318 @Nullable C next = domain.next(endpoint);
319 return (next == null) ? Cut.<C>belowAll() : belowValue(next);
320 default:
321 throw new AssertionError();
322 }
323 }
324 @Override Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) {
325 switch (boundType) {
326 case OPEN:
327 @Nullable C next = domain.next(endpoint);
328 return (next == null) ? Cut.<C>aboveAll() : belowValue(next);
329 case CLOSED:
330 return this;
331 default:
332 throw new AssertionError();
333 }
334 }
335 @Override void describeAsLowerBound(StringBuilder sb) {
336 sb.append('(').append(endpoint);
337 }
338 @Override void describeAsUpperBound(StringBuilder sb) {
339 sb.append(endpoint).append(']');
340 }
341 @Override C leastValueAbove(DiscreteDomain<C> domain) {
342 return domain.next(endpoint);
343 }
344 @Override C greatestValueBelow(DiscreteDomain<C> domain) {
345 return endpoint;
346 }
347 @Override Cut<C> canonical(DiscreteDomain<C> domain) {
348 C next = leastValueAbove(domain);
349 return (next != null) ? belowValue(next) : Cut.<C>aboveAll();
350 }
351 @Override public int hashCode() {
352 return ~endpoint.hashCode();
353 }
354 @Override public String toString() {
355 return "/" + endpoint + "\\";
356 }
357 private static final long serialVersionUID = 0;
358 }
359 }